import { unstable_batchedUpdates } from "react-dom"

/* 对外接口 form一共又如下API  */
const formInstanceApi = [
    'setCallback',
    'dispatch',
    'registerValidateFields',
    'resetFields',
    'setFields',
    'setFieldsValue',
    'getFieldsValue',
    'getFieldValue',
    'validateFields',
    'submit',
    'unRegisterValidate'
]

/* 判断是否是正则表达式 */
const isReg = (value) => value instanceof RegExp

class FormStore {
    // 初始化表单数据
    constructor(forceUpdate, defaultFormValue = {}) {
        this.forceUpdate = forceUpdate
        this.model = {}  // 表单状态层
        this.control = {} // 控制每个formItem的控制器
        this.isSchedule = false // 开启调度
        this.callback = {}  //存放监听函数callback
        this.penddingValidateQueue = []  // 批量更新队列
        this.defaultFormValue = defaultFormValue  // 表单初始化值
    }

    // 获取form的api
    getForm() {
        return formInstanceApi.reduce((map, item) => {
            // 把可以提供出去的API, 进行组装，并绑定当前的this
            map[item] = this[item].bind(this)
            // 一定要return出去
            return map
        }, {})
    }

    // 处理回调函数
    setCallback(cb) {
        // console.log('callbacl ==> ', cb)
        this.callback = cb
    }

    // 创建一个验证 Validate 
    // model 下的每一个模块，主要在注册表单单元项的时候使用。
    static createValidate(validate) {
        const { value, rule, required, message } = validate

        return {
            value,
            rule: rule || (() => true),  // 如果没有规则，默认就是通过
            required: required || false, // 默认不必填
            message: message || '',
            status: 'pending',  // 根据promise设计结构，设计状态
        }
    }

    // 注册表单单元项
    // 注册表单单元项，这个在 FormItem 初始化时候调用
    // 把验证信息，验证文案，等信息，通过 ·createValidate 注册到 model 中
    registerValidateFields(name, control, model) {
        // 如果注册的fromitem设置了默认值
        if (this.defaultFormValue[name]) {
            model = this.defaultFormValue[name]
        }
        // 注册验证表单方法
        const validate = FormStore.createValidate(model)
        this.model[name] = validate
        // 存放控制每一个formItem更新的方法
        this.control[name] = control
        // console.log('this.model ====> ', this.model)
        // console.log('this.control ====> ', this.control)
    }

    // 卸载注册表单单元项 
    // 在 FormItem 的生命周期销毁阶段执行，解绑上面 registerValidateFields 注册的内容
    unRegisterValidate(name) {
        delete this.model[name]
        delete this.control[name]
    }

    // 触发更新事件 (当表单数据修改时、触发dispatch完成更新)
    dispatch(action, ...args) {
        // 如果action 的类型不是对象 直接返回null
        if (!action && typeof action !== 'object') return null

        const { type } = action

        // console.log('dispatch ==> ', action)
        // ~ 位运算符操作，不要将实现方法暴露出去
        if (~formInstanceApi.indexOf(type)) {
            // 如果方法是form的API，那么执行他
            return this[type](...args)
        } else if (typeof this[type] === 'function') {
            // 如果方法是个函数，那么执行他
            return this[type](...args)
        }
    }


    // 通知对应的 FormItem 更新
    notifyChange(name) {
        const controller = this.control[name]
        // 如果有控制器 就调用 changeValue 完成更新
        if (controller) controller?.changeValue()
    }

    // 重置表单
    resetFields() {
        Object.keys(this.model).forEach(modelName => {
            // 重置每一项
            this.setValueClearStatus(this.model[modelName], modelName, null)
        })
    }

    // 设置一组字段状态
    setFields(object) {
        // 如果不是对象，就直接返回
        if (typeof object !== 'object') return
        object.keys(object).forEach(modelName => {
            // 分别设置
            this.setFieldsValue(modelName, object[modelName])
        })
    }

    // 设置表单值
    setFieldsValue(name, modelValue) {
        const model = this.model[name]
        if (!model) return false
        if (typeof modelValue === 'object') {
            const { message, rule, value } = modelValue
            // 分别给model设置属性
            if (message) model.message = message
            if (rule) model.rule = rule
            if (value) model.value = value
            model.status = 'pending'              /* 设置待验证状态 */
            this.validateFieldValue(name, true)     /* 如果重新设置了验证规则，那么重新验证一次 */
        } else {
            this.setValueClearStatus(model, name, modelValue)
        }
    }

    // 复制并清空状态
    setValueClearStatus(model, name, value) {
        model.value = value
        model.status = 'pendding'
        // 通知指定name更新
        this.notifyChange(name)
    }

    // 获取表单数据层的值
    getFieldsValue() {
        const formData = {}
        // 可以转换成 reduce 形式
        Object.keys(this.model).forEach(modelName => {
            formData[modelName] = this.model[modelName].value
        })
        return formData
    }

    // 获取表单模型
    getFieldModel(name) {
        const model = this.model[name]
        return model || {}
    }

    // 获取指定字段的值
    getFieldValue(name) {
        const model = this.model[name]
        // 没有model  但是有默认值
        if (!model && this.defaultFormValue[name]) {
            return this.defaultFormValue[name]
        }
        // 注册了model 直接返回value
        return model ? model.value : null
    }

    // 验证一个表单 
    // name 验证谁
    // forceUpdate 验证完是否立即更新
    validateFieldValue(name, forceUpdate) {
        const model = this.model[name]
        // 记录上一次的状态
        const lastStatus = model.status
        // 如果没有model模型 无法进行验证
        if (!model) return

        const { required, rule, value } = model

        let status = 'resolve'
        if (required && !value) {
            status = 'reject'
        } else if (isReg(rule)) {
            // 正则校验规则
            status = rule.test(value) ? 'resolve' : 'reject'
        } else if (typeof rule === 'function') {
            // 自定义校验规则
            status = rule(value) ? 'resolve' : 'reject'
        }

        model.status = status

        if (lastStatus !== status || forceUpdate) {
            const notify = this.notifyChange.bind(this, name)
            // 放入到更新队列中
            this.penddingValidateQueue.push(notify)
        }
        // 调度更新
        this.scheduleValidate()
        return status
    }

    // 调度验证更新任务 完成更新
    scheduleValidate() {
        // 是否开启了调度
        if (this.isSchedule) return
        // 表示电镀更新一开始
        this.isSchedule = true

        Promise.resolve().then(() => {
            unstable_batchedUpdates(() => {
                do {
                    // 从头挨个个执行
                    let notify = this.penddingValidateQueue.shift()
                    notify && notify()
                } while (this.penddingValidateQueue.length > 0)
                // 执行完毕 关闭调度
                this.isSchedule = false
            })
        })
    }

    // 验证整个表单
    validateFields(callback) {
        let status = true
        Object.keys(this.model).forEach(modelName => {
            const modelStates = this.validateFieldValue(modelName, true)
            if (modelStates == 'reject') {
                status = false
            }
        })

        callback(status)
    }

    // 提交表单
    submit(cb) {
        this.validateFields(res => {
            const { onFinish, onFinishFailed } = this.callback
            // 把验证结果返回给 回调
            cb && cb(res)
            // 验证失败 回调 onFinishFailed
            if (!res && onFinishFailed && typeof onFinishFailed === 'function') {
                onFinishFailed()
            }
            // 验证成功 回调 onFinishFailed
            if (res && onFinish && typeof onFinish === 'function') {
                onFinish(this.getFieldsValue())
            }
        })
    }
}

export default FormStore